package org.example.guava;

import com.google.common.cache.*;
import org.junit.Test;

import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @Classname GuavaCache
 * @Description guava缓存
 * @Date 2020/12/21 10:12 上午
 * @Created by xiangjd
 */
public class GuavaCache {

    @Test
    public void test1(){
        Cache<String,String> cache = CacheBuilder.newBuilder().build();
        cache.put("word","Hello Guava Cache");
        System.out.println(cache.getIfPresent("word"));
    }

    /**
     * 设置缓存的大小，当超过大小时删除最先开始put的那一个元素
     */
    @Test
    public void test2(){
        Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(2).build();
        cache.put("key1","value1");
        cache.put("key2","value2");
        cache.put("key3","value3");
        System.out.printf("key1的value为:%s%n", cache.getIfPresent("key1"));
        System.out.printf("key2的value为:%s%n", cache.getIfPresent("key2"));
        System.out.printf("key3的value为:%s%n", cache.getIfPresent("key3"));
    }

    /**
     * expireAfterWrite方法指定对象被写入到缓存后多久过期
     */
    @Test
    public void test3() {
        Cache<String, String> cache = CacheBuilder.newBuilder()
                .maximumSize(2)
                .expireAfterWrite(3, TimeUnit.SECONDS)
                .build();
        cache.put("key1", "value1");
        int time = 1;
        while (true) {
            System.out.println("第" + time++ + "次从缓存取到key为key1的value值为" + cache.getIfPresent("key1"));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * expireAfterAccess指定对象多久没有被访问后过期。
     */
    @Test
    public void test4() {
        Cache<String, String> cache = CacheBuilder.newBuilder()
                .maximumSize(2)
                .expireAfterAccess(3, TimeUnit.SECONDS)
                .build();
        cache.put("key1", "value1");
        int time = 1;
        while (true) {
            try {
                Thread.sleep(time * 1000);
                System.out.println("第" + time++ + "次从缓存取到key等于key1它对应的value值为" + cache.getIfPresent("key1"));
                ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 构建Cache时通过weakValues方法指定Cache只保存记录值的一个弱引用。
     * 当给value引用赋值一个新的对象之后，就不再有任何一个强引用指向原对象。
     * System.gc()触发垃圾回收后，原对象就被清除了。
     */
    @Test
    public void test5() {
        Cache<String, Object> cache = CacheBuilder.newBuilder()
                .maximumSize(2)
                .weakValues()
                .build();
        Object o = new Object();
        cache.put("key1", o);

        o = new Object();//原对象不在有强引用
        System.gc();
        System.out.println("从弱引用values取值为" + cache.getIfPresent("key1"));

    }

    /**
     * 可以调用Cache的invalidateAll或invalidate方法显示删除Cache中的记录。
     * invalidate方法一次只能删除Cache中一个记录，接收的参数是要删除记录的key。
     * invalidateAll方法可以批量删除Cache中的记录，当没有传任何参数时，invalidateAll方法将清除Cache中的全部记录。
     * invalidateAll也可以接收一个Iterable类型的参数，参数中包含要删除记录的所有key值。下面代码对此做了示例。
     */
    @Test
    public void test6(){
        Cache<String, String> cache = CacheBuilder.newBuilder().build();
        cache.put("key1","value1");
        cache.put("key2","value2");
        cache.put("key3","value3");

        ArrayList<String> list = new ArrayList<>();
        list.add("key1");
        list.add("key2");

        cache.invalidateAll(list);
        System.out.println("缓存key1的value值为"+cache.getIfPresent("key1"));
        System.out.println("缓存key2的value值为"+cache.getIfPresent("key2"));
        System.out.println("缓存key3的value值为"+cache.getIfPresent("key3"));
    }

    /**
     * 移除监听器
     */
    @Test
    public void test7(){
        RemovalListener<String, String> listener = new RemovalListener<String, String>() {
            @Override
            public void onRemoval(RemovalNotification<String, String> notification) {
                System.out.println("[" + notification.getKey() + ":" + notification.getValue() + "] is removed!");
            }
        };
        Cache<String,String> cache = CacheBuilder.newBuilder()
                .maximumSize(3)
                .removalListener(listener)
                .build();
        Object value = new Object();
        cache.put("key1","value1");
        cache.put("key2","value2");
        cache.put("key3","value3");
        cache.put("key4","value3");
        cache.put("key5","value3");
        cache.put("key6","value3");
        cache.put("key7","value3");
        cache.put("key8","value3");
    }

    /**
     * 调整缓存设置是至关重要的，在性能要求高的应用中应该密切关注这些数据
     */
    @Test
    public void test8(){
        Cache<String, String> cache = CacheBuilder.newBuilder()
                .maximumSize(3)
                .recordStats()
                .build();

        cache.put("key1","value1");
        cache.put("key2","value2");
        cache.put("key3","value3");
        cache.put("key4","value4");

        cache.getIfPresent("key1");
        cache.getIfPresent("key2");
        cache.getIfPresent("key3");
        cache.getIfPresent("key4");
        cache.getIfPresent("key5");
        cache.getIfPresent("key6");

        System.out.println(cache.stats());
    }

    /**
     * 当缓存对应的key不存在时，调用CacheLoader的load方法进行加载返回
     */
    @Test
    public void test9() {
        CacheLoader<String, String> loader = new CacheLoader<String, String>() {
            @Override
            public String load(String key) throws Exception {
                Thread.sleep(1000); //休眠1s，模拟加载数据
                System.out.println(key + " is loaded from a cacheLoader!");
                return key + "is value";
            }
        };

        LoadingCache<String, String> loadingCache = CacheBuilder.newBuilder()
                .maximumSize(3)
                .build(loader);//在构建时指定自动加载器

        try {
            loadingCache.get("key1");
            loadingCache.get("key2");
            loadingCache.get("key3");
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}
